package nsu.edu.zsq.service.impl.sys;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Random;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

import nsu.edu.zsq.bean.SchRoom;
import nsu.edu.zsq.bean.SchRoomExample;
import nsu.edu.zsq.bean.StuCourse;
import nsu.edu.zsq.bean.StuCourseExample;
import nsu.edu.zsq.bean.TchCourse;
import nsu.edu.zsq.common.RequestHolder;
import nsu.edu.zsq.dao.SchRoomMapper;
import nsu.edu.zsq.dao.StuCourseMapper;
import nsu.edu.zsq.dao.TchCourseMapper;
import nsu.edu.zsq.exception.ParamException;
import nsu.edu.zsq.param.PageQuery;
import nsu.edu.zsq.param.TchCourseParam;
import nsu.edu.zsq.service.SchRoomManageService;
import nsu.edu.zsq.service.sys.StudentCourseService;
import nsu.edu.zsq.service.sys.SysLogService;
import nsu.edu.zsq.util.BeanValidator;

/** 
* Description: 学生课程的service实现类<br>
*/
@Service
public class StudentCourseServiceImpl implements StudentCourseService {

    @Autowired
    private StuCourseMapper stuCourseMapper;
    @Autowired
    private TchCourseMapper tchCourseMapper;
    @Autowired
    private SysLogService sysLogService;
    @Autowired
    private SchRoomManageService schRoomManageService;
    @Autowired
    private SchRoomMapper schRoomMapper;
    
    @Override
    public StuCourse getStuCourse(int id) {
        StuCourse stuCourse = stuCourseMapper.getStuCourseByPrimaryKey(id);
        return stuCourse;
    }
    
    @Override
    public List<Map<String, Integer>> countCourseByClass() {
        List<Map<String, Integer>> countCourse = stuCourseMapper.countCourseByClass();
        return countCourse;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveBatchStuCourse(int[] tchCourseIds, int classId) {
        List<StuCourse> after = new ArrayList<StuCourse>();
        for (int tchCourseId : tchCourseIds) {
            // 1.查询教师课程信息
            TchCourse tchCourse = tchCourseMapper.selectByPrimaryKey(tchCourseId);
            StuCourse afterTuCourse = StuCourse.builder().classId(classId).tchCourseId(tchCourseId)
                    .courseType(tchCourse.getCourseType()).courseNo(tchCourse.getCourseNo())
                    .courseName(tchCourse.getCourseName()).teacherName(tchCourse.getTeacherNo())
                    .operator(RequestHolder.getCurrentSysUser().getAccount())
                    .operatorTime(new Date()).build();
            after.add(afterTuCourse);
            // 2.检查该班级是否已经存在该课程
            if (checkCourseExist(tchCourse.getCourseNo(), classId)) {
                throw new ParamException("不可重复添加课程["+tchCourse.getCourseName()+"]");
            }
            // 课程一周次数
            int number = tchCourse.getNumber();
            // 3.根据课程次数，生成对于数量的课程
            for (int i= 0; i < number; i++) {
                stuCourseMapper.insertSelective(afterTuCourse);
            }
        }
        
        // 4.添加日志
        String instruction = null;
        if (tchCourseIds.length > 1) {
            instruction = "学生课程管理-课程管理-添加课程-批量添加";
        } else {
            instruction = "学生课程管理-课程管理-添加课程-单个添加";
        }
        sysLogService.saveSysLogBySysUser(null, after, instruction);
    }

    /**
     * 检查该班级是否已经存在该课程
     * @param courseNo 课程代码
     * @param classId 班级id
     * @return boolean true：存在 false：不存在
     */
    private boolean checkCourseExist(String courseNo, int classId) {
        StuCourseExample example = new StuCourseExample();
        example.createCriteria().andClassIdEqualTo(classId).andCourseNoEqualTo(courseNo);
        return stuCourseMapper.countByExample(example) > 0;
    }

    @Override
    public List<StuCourse> listClassCourse(int classId) {
        List<StuCourse> listClassCourse = stuCourseMapper.listClassCourse(classId);
        return listClassCourse;
    }
    
    @Override
    public PageInfo<TchCourseParam> listTchCourse(String majorNo, PageQuery pageQuery) {
        PageHelper.startPage(pageQuery.getPageNum(),pageQuery.getPageSize());
        List<TchCourseParam> listTchCourseParam = tchCourseMapper.listTchCourseParamByMajorNo(majorNo);
        PageInfo<TchCourseParam> pageInfo = new PageInfo<TchCourseParam>(listTchCourseParam, pageQuery.getNavigatePages());
        return pageInfo;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteStuCourse(int[] courseIds) {
        List<StuCourse> before = new ArrayList<StuCourse>();
        for (int courseId : courseIds) {
            StuCourse stuCourse = getStuCourse(courseId);
            before.add(stuCourse);
            // 删除时，要把多个节数课程同时删除，所以这里根据课程代码删除
            StuCourseExample example = new StuCourseExample();
            example.createCriteria().andCourseNoEqualTo(stuCourse.getCourseNo());
            stuCourseMapper.deleteByExample(example);
            // 同时删除掉被占用的教室资源
            schRoomManageService.deleteCourseFromSchRoom(courseId, stuCourse.getCourseType());
        }
        
        // 添加日志
        String instruction = null;
        if (courseIds.length > 1) {
            instruction = "学生课程管理-课程管理-批量删除";
        } else if (courseIds.length == 1) {
            instruction = "学生课程管理-课程管理-单个删除";
        }
        sysLogService.saveSysLogBySysUser(before, null, instruction);
    }
    
    /**
     * 获取所有空闲的不是910节学校教室
     * @return List<SchRoom>
     */
    private List<SchRoom> listFreeSchRoom() {
        SchRoomExample example = new SchRoomExample();
        nsu.edu.zsq.bean.SchRoomExample.Criteria createCriteria = example.createCriteria();
        // 1.选择无课的教室,必修课不能910节
        createCriteria.andCourseIdEqualTo(0).andCourseTimeNotEqualTo("910");
        List<SchRoom> listSchRoom = schRoomMapper.selectByExample(example);
        return listSchRoom;
    }
    
    /**
     * 检查上课时间是否和教师的时间冲突<br>
     * 需要数据：teacherName,startDy,startTime
     * @param stuCourse 学生课程信息
     * @return boolean true：冲突 false：不冲突
     */
    private boolean checkTeacherTimeConflict(StuCourse stuCourse) {
        StuCourseExample example = new StuCourseExample();
        example.createCriteria().andTeacherNameEqualTo(stuCourse.getTeacherName()).andStartDayEqualTo(stuCourse.getStartDay())
            .andStartTimeEqualTo(stuCourse.getStartTime());
        return stuCourseMapper.countByExample(example) > 0;
    }
    
    /**
     * 检查上课时间是否和班级的上课时间冲突<br>
     * 需要数据：classId,startDy,startTime
     * @param stuCourse 学生课程信息
     * @return boolean true：冲突 false：不冲突
     */
    private boolean checkClassTimeConflict(StuCourse stuCourse) {
        StuCourseExample example = new StuCourseExample();
        example.createCriteria().andClassIdEqualTo(stuCourse.getClassId()).andStartDayEqualTo(stuCourse.getStartDay())
        .andStartTimeEqualTo(stuCourse.getStartTime());
    return stuCourseMapper.countByExample(example) > 0;
    }

    @Override
    public void updateStuCourse(StuCourse stuCourse) {
        BeanValidator.check(stuCourse);
        StuCourse before = stuCourseMapper.selectByPrimaryKey(stuCourse.getId());
        stuCourse.setTeacherName(before.getTeacherName());
        stuCourse.setClassId(before.getClassId());
        // 1.检查是否有该教室
        if (!checkRoomNameExist(stuCourse.getRoomName())) {
            throw new ParamException("该教室不存在，请重新输入");
        }
        // 2.检查是否和授课教师的时间冲突
        if (checkTeacherTimeConflict(stuCourse)) {
            throw new ParamException("与授课教师时间安排冲突");
        }
        // 3.检查是否和该班级时间冲突
        if (checkClassTimeConflict(stuCourse)) {
            throw new ParamException("与班级其它课程时间安排冲突");
        }
        // 4.删除之前的教室占用
        schRoomManageService.deleteCourseFromSchRoom(before.getId(), before.getCourseType());
        // 5.添加现在的教室占用
        TchCourse tchCourse = TchCourse.builder().id(stuCourse.getId()).startDay(stuCourse.getStartDay())
                .startTime(stuCourse.getStartTime()).roomName(stuCourse.getRoomName()).build();
        schRoomManageService.saveCourseToSchRoom(tchCourse);
        // 6.更新学生课程信息
        stuCourseMapper.updateByPrimaryKeySelective(stuCourse);
        
        // 7.添加日志
        String instruction = "学生课程管理-课表安排-自动排课";
        sysLogService.saveSysLogBySysUser(before, stuCourse, instruction);
    }

    /**
     * 检查教室是否存在
     * @param roomName 教室名称
     * @return boolean true：存在 false：不存在
     */
    private boolean checkRoomNameExist(String roomName) {
        SchRoomExample example = new SchRoomExample();
        example.createCriteria().andRoomNameEqualTo(roomName);
        return schRoomMapper.countByExample(example) > 0;
    }
    
	/*
	 * @Transactional(rollbackFor = Exception.class)
	 * 
	 * @Override public void autoStuCourse(int[] stuCourseIds) { List<StuCourse>
	 * before = new ArrayList<StuCourse>(); List<StuCourse> after = new
	 * ArrayList<StuCourse>(); for (int stuCourseId : stuCourseIds) { StuCourse
	 * beforeStuCourse = stuCourseMapper.selectByPrimaryKey(stuCourseId);
	 * before.add(beforeStuCourse); // 1.获取所有空闲教室 List<SchRoom> listFreeSchRoom =
	 * listFreeSchRoom(); Random random = new Random(); // 2.随机获取一个空闲的教室 StuCourse
	 * stuCourse = new StuCourse(); for (int i = 0; i < listFreeSchRoom.size(); i++)
	 * { SchRoom schRoom =
	 * listFreeSchRoom.get(random.nextInt(listFreeSchRoom.size())); stuCourse =
	 * StuCourse.builder().teacherName(beforeStuCourse.getTeacherName()).classId(
	 * beforeStuCourse.getClassId())
	 * .id(beforeStuCourse.getId()).roomName(schRoom.getRoomName())
	 * .startDay(Integer.valueOf(schRoom.getCourseWeek()))
	 * .startTime(Integer.valueOf(schRoom.getCourseTime()))
	 * .operator(RequestHolder.getCurrentSysUser().getAccount()) .operatorTime(new
	 * Date()).build(); // 3.检查是否和授课教师的时间冲突:冲突则继续随机教室 if
	 * (checkTeacherTimeConflict(stuCourse)) { continue; } //
	 * 4.检查是否和该班级时间冲突：不冲突则直接跳出循环 if (!checkClassTimeConflict(stuCourse)) { break; }
	 * } // 5.删除之前的教室占用
	 * schRoomManageService.deleteCourseFromSchRoom(beforeStuCourse.getId(),
	 * beforeStuCourse.getCourseType()); // 6.添加现在的教室占用 TchCourse tchCourse =
	 * TchCourse.builder().id(stuCourse.getId()).startDay(stuCourse.getStartDay())
	 * .startTime(stuCourse.getStartTime()).roomName(stuCourse.getRoomName()).build(
	 * ); schRoomManageService.saveCourseToSchRoom(tchCourse); // 7.更新学生课程信息
	 * stuCourseMapper.updateByPrimaryKeySelective(stuCourse); after.add(stuCourse);
	 * } // 8.添加日志 String instruction = "学生课程管理-课表安排-自动排课";
	 * sysLogService.saveSysLogBySysUser(before, after, instruction); }
	 */
}
